{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n# Path effects guide\n\n\nDefining paths that objects follow on a canvas.\n\n.. py:module:: matplotlib.patheffects\n\n\nMatplotlib's :mod:`~matplotlib.patheffects` module provides functionality to\napply a multiple draw stage to any Artist which can be rendered via a\n:class:`~matplotlib.path.Path`.\n\nArtists which can have a path effect applied to them include :class:`~matplotlib.patches.Patch`,\n:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.collections.Collection` and even\n:class:`~matplotlib.text.Text`. Each artist's path effects can be controlled via the\n``set_path_effects`` method (:class:`~matplotlib.artist.Artist.set_path_effects`), which takes\nan iterable of :class:`AbstractPathEffect` instances.\n\nThe simplest path effect is the :class:`Normal` effect, which simply\ndraws the artist without any effect:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\nimport matplotlib.patheffects as path_effects\n\nfig = plt.figure(figsize=(5, 1.5))\ntext = fig.text(0.5, 0.5, 'Hello path effects world!\\nThis is the normal '\n                          'path effect.\\nPretty dull, huh?',\n                ha='center', va='center', size=20)\ntext.set_path_effects([path_effects.Normal()])\nplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Whilst the plot doesn't look any different to what you would expect without any path\neffects, the drawing of the text now been changed to use the path effects\nframework, opening up the possibilities for more interesting examples.\n\nAdding a shadow\n---------------\n\nA far more interesting path effect than :class:`Normal` is the\ndrop-shadow, which we can apply to any of our path based artists. The classes\n:class:`SimplePatchShadow` and\n:class:`SimpleLineShadow` do precisely this by drawing either a filled\npatch or a line patch below the original artist:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import matplotlib.patheffects as path_effects\n\ntext = plt.text(0.5, 0.5, 'Hello path effects world!',\n                path_effects=[path_effects.withSimplePatchShadow()])\n\nplt.plot([0, 3, 2, 5], linewidth=5, color='blue',\n         path_effects=[path_effects.SimpleLineShadow(),\n                       path_effects.Normal()])\nplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice the two approaches to setting the path effects in this example. The\nfirst uses the ``with*`` classes to include the desired functionality automatically\nfollowed with the \"normal\" effect, whereas the latter explicitly defines the two path\neffects to draw.\n\nMaking an artist stand out\n--------------------------\n\nOne nice way of making artists visually stand out is to draw an outline in a bold\ncolor below the actual artist. The :class:`Stroke` path effect\nmakes this a relatively simple task:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(7, 1))\ntext = fig.text(0.5, 0.5, 'This text stands out because of\\n'\n                          'its black border.', color='white',\n                          ha='center', va='center', size=30)\ntext.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'),\n                       path_effects.Normal()])\nplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is important to note that this effect only works because we have drawn the text\npath twice; once with a thick black line, and then once with the original text\npath on top.\n\nYou may have noticed that the keywords to :class:`Stroke` and\n:class:`SimplePatchShadow` and :class:`SimpleLineShadow` are not the usual Artist\nkeywords (such as ``facecolor`` and ``edgecolor`` etc.). This is because with these\npath effects we are operating at lower level of matplotlib. In fact, the keywords\nwhich are accepted are those for a :class:`matplotlib.backend_bases.GraphicsContextBase`\ninstance, which have been designed for making it easy to create new backends - and not\nfor its user interface.\n\n\nGreater control of the path effect artist\n-----------------------------------------\n\nAs already mentioned, some of the path effects operate at a lower level than most users\nwill be used to, meaning that setting keywords such as ``facecolor`` and ``edgecolor``\nraise an AttributeError. Luckily there is a generic :class:`PathPatchEffect` path effect\nwhich creates a :class:`~matplotlib.patches.PathPatch` class with the original path.\nThe keywords to this effect are identical to those of :class:`~matplotlib.patches.PathPatch`:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(8, 1))\nt = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center')\nt.set_path_effects([path_effects.PathPatchEffect(offset=(4, -4), hatch='xxxx',\n                                                 facecolor='gray'),\n                    path_effects.PathPatchEffect(edgecolor='white', linewidth=1.1,\n                                                 facecolor='black')])\nplt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "..\n    Headings for future consideration:\n\n    Implementing a custom path effect\n    ---------------------------------\n\n    What is going on under the hood\n    --------------------------------\n\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
